﻿Public Class Map

    Public Enum LandType
        Ocean
        Plains
        Mountain
        Foothills
        Marsh
        River
        Undefined
    End Enum
    Public Enum BonusType
        Fish
        Grain
        Sugar
        Tobacco
        Wood
        Cattle
        None
    End Enum
    Public Class MapTileType
        Implements ICloneable
        Property Land As LandType = LandType.Ocean
        Property Bonus As BonusType = BonusType.None
        Property UnitID As Integer = 0
        Function Clone() As Object Implements System.ICloneable.Clone
            Return DirectCast(MemberwiseClone(), MapTileType)
        End Function
    End Class

    Dim _Map(1, 1) As MapTileType

    Default ReadOnly Property Tile(ByVal x As Integer, ByVal y As Integer) As MapTileType
        Get
            If (x - 1) <= UBound(_Map, 2) AndAlso x > 0 AndAlso (y - 1) <= UBound(_Map, 1) AndAlso y > 0 Then
                Return _Map(x - 1, y - 1)
            Else
                Return New MapTileType With {.Land = LandType.Undefined, .Bonus = BonusType.None}
            End If
        End Get
    End Property

    Public Property Height As Integer
    Public Property Width As Integer

    Public Sub New(Optional NewHeight As Integer = 100, Optional NewWidth As Integer = 0, Optional Margin As Integer = 3)
        Dim r As New Random
        _Height = NewHeight
        _Width = NewWidth
        If _Height <= Margin * 2 Then _Height = Margin * 2 + 1
        If _Width <= Margin * 2 Then _Width = Margin * 2 + 1
        If NewWidth = 0 Then Width = _Height

        Dim tempMap(_Height - 1, _Width - 1) As MapTileType
        Dim t As New MapTileType
        For H As Integer = 0 To _Height - 1
            For W As Integer = 0 To _Width - 1
                tempMap(H, W) = t.Clone                
            Next
        Next
        t = Nothing
        _Map = tempMap.Clone
        tempMap = Nothing

        'Generate Land        
        Dim iLandMass As Integer = r.NextDouble * _Height * _Width  'TotalNumber of Land Tiles
        If iLandMass < 50 Then iLandMass += 50
        Dim iCurrX As Integer = _Width \ 2      'Start in the Center
        Dim iCurrY As Integer = _Height \ 2     'Start in the Center

        _Map(iCurrY - 1, iCurrX - 1).Land = LandType.Plains  'Set center tile to Plains        
        Dim bMapIt As Boolean = True
        Dim iCount As Integer = 1               'Count up to Total landmass
        While iCount <= iLandMass
            bMapIt = True
            Select Case Int(r.NextDouble * 3)  'North/South/NoMove                
                Case 1
                    If iCurrY > Margin Then
                        iCurrY -= 1
                    Else
                        randomMove(r, iCurrX, iCurrY, bMapIt, Margin) 'Because we hit an edge
                    End If
                Case 2
                    If iCurrY < _Height - Margin Then
                        iCurrY += 1
                    Else
                        randomMove(r, iCurrX, iCurrY, bMapIt, Margin)
                    End If                                    
            End Select
            Select Case Int(r.NextDouble * 3)  'East/West/NoMove
                Case 1
                    If iCurrX > Margin Then
                        iCurrX -= 1
                    Else
                        randomMove(r, iCurrX, iCurrY, bMapIt, Margin)
                    End If
                Case 2
                    If iCurrX < _Width - Margin Then
                        iCurrX += 1
                    Else
                        randomMove(r, iCurrX, iCurrY, bMapIt, Margin)
                    End If                                    
            End Select
            If bMapIt AndAlso _Map(iCurrY - 1, iCurrX - 1).Land <> LandType.Plains Then
                _Map(iCurrY - 1, iCurrX - 1).Land = LandType.Plains
                Select Case Int(r.NextDouble * 10)
                    Case 1
                        _Map(iCurrY - 1, iCurrX - 1).Bonus = Int(r.NextDouble * 5) + 1
                End Select
                iCount += 1
            End If
        End While

        'Cleanup Orphans, Add Fish
        For iCurrY = Margin To _Height - Margin
            For iCurrX = Margin To _Width - Margin
                Select Case _Map(iCurrY - 1, iCurrX - 1).Land
                    Case LandType.Plains
                        If _Map(iCurrY - 1, iCurrX).Land = LandType.Ocean AndAlso
                           _Map(iCurrY - 1, iCurrX - 2).Land = LandType.Ocean AndAlso
                           _Map(iCurrY, iCurrX - 1).Land = LandType.Ocean AndAlso
                           _Map(iCurrY - 2, iCurrX - 1).Land = LandType.Ocean Then _Map(iCurrY - 1, iCurrX - 1).Land = LandType.Ocean
                    Case LandType.Ocean
                        If _Map(iCurrY - 1, iCurrX).Land = LandType.Plains OrElse _Map(iCurrY - 1, iCurrX - 2).Land = LandType.Plains Then
                            If Int(r.NextDouble * 20) = 1 Then _Map(iCurrY - 1, iCurrX - 1).Bonus = BonusType.Fish
                        End If
                    End Select
            Next
        Next

    End Sub
    Private Sub randomMove(ByVal r As Random, ByRef CurrX As Integer, ByRef CurrY As Integer, ByRef MapIt As Boolean, ByVal Margin As Integer)
        CurrX = r.NextDouble * _Width
        CurrY = r.NextDouble * _Height
        While CurrX < Margin Or CurrX > _Width - Margin
            CurrX = r.NextDouble * _Width
        End While
        While CurrY < Margin Or CurrY > _Height - Margin
            CurrY = r.NextDouble * _Height
        End While
        MapIt = False
    End Sub
End Class
